package com.hg.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.hg.common.dto.DeptDTO;
import com.hg.common.dto.PageDTO;
import com.hg.common.enums.ResultEnum;
import com.hg.common.enums.StateEnum;
import com.hg.common.exception.BizException;
import com.hg.common.vo.DeptVO;
import com.hg.entity.Dept;
import com.hg.entity.DeptExample;
import com.hg.mapper.DeptMapper;
import com.hg.service.IDeptService;
import com.hg.util.ValidateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * 部门 服务实现类
 * Created by skh on 2018/1/10
 */
@Service
@Transactional
@Slf4j
public class DeptServiceImpl implements IDeptService {

	public static final String ROOT_LEVEL = "0,";


	@Autowired
	private DeptMapper deptMapper;

	@Override
	public void save(DeptVO deptVO) {

		//校验参数
		ValidateUtil.validate(deptVO);

		//校验同级部门名字是否重复
		Boolean isExist = checkNameExist(deptVO.getName(), deptVO.getParentId(), deptVO.getId());
		if (isExist) {
			log.error("[校验同级部门名字是否重复]异常:deptVO:{}", deptVO);
			throw new BizException(ResultEnum.DEPT_NAME_DUPLICATE);
		}

		//填充属性
		Dept dept = new Dept();
		BeanUtils.copyProperties(deptVO, dept);

		//查找父部门
		Dept parentDept = deptMapper.selectByPrimaryKey(deptVO.getParentId());
		//计算level
		String level = calculateLevel(parentDept);
		log.debug("新增部门的level值 = {}", level);
		dept.setLevel(level);

		//todo 等用户模块
		dept.setCreateBy("admin");
		dept.setUpdateBy("admin");


		deptMapper.insertSelective(dept);
	}

	@Override
	public void update(DeptVO deptVO) {
		ValidateUtil.validate(deptVO);

		Dept before = deptMapper.selectByPrimaryKey(deptVO.getId());
		Preconditions.checkNotNull(before, "id="+deptVO.getId()+"部门不存在", deptVO);

		//校验同级部门名字是否重复
		Boolean exist = checkNameExist(deptVO.getName(), deptVO.getParentId(), deptVO.getId());
		if (exist) {
			log.error("[校验同级部门名字是否重复]异常:deptVO:{}", deptVO);
			throw new BizException(ResultEnum.DEPT_NAME_DUPLICATE);
		}

		//填充属性
		Dept after = new Dept();
		BeanUtils.copyProperties(deptVO, after);

		//查找父部门
		Dept parentDept = deptMapper.selectByPrimaryKey(deptVO.getParentId());
		//计算level
		String level = calculateLevel(parentDept);
		after.setLevel(level);
		//todo 用户
		after.setUpdateBy("admin");

		log.debug("更新前的部门:{}",before);
		log.debug("更新后的部门:{}",after);

		//修改当前部门和子部门
		updateWithChild(before, after);


	}

	@Override
	public void delete(Integer deptId) {
		Dept dept = deptMapper.selectByPrimaryKey(deptId);
		if (dept == null) {
			throw new BizException(ResultEnum.DEPT_NOT_EXIST);
		}
		//判断当前部门下面是否有子部门,有则无法删除
		List<Dept> deptList = selectDeptListByParentId(deptId);
		if (CollectionUtils.isNotEmpty(deptList)) {
			throw new BizException(ResultEnum.HAVE_CHILD_DEPT);
		}

		//判断当前部门下面是否有用户,有则无法删除
		//todo

		deptMapper.deleteByPrimaryKey(deptId);
	}


	private List<Dept> selectDeptListByParentId(Integer parentId) {
		DeptExample example = new DeptExample();
		DeptExample.Criteria criteria = example.createCriteria();
		criteria.andParentIdEqualTo(parentId);

		List<Dept> deptList = deptMapper.selectByExample(example);
		return deptList;
	}

	/**
	 * 查询指定部门下的所有子部门列表
	 * @return
	 */
	private List<Dept> selectAllChildDeptList(Integer deptId){
		Dept dept = deptMapper.selectByPrimaryKey(deptId);
		String queryLevel = dept.getLevel()+dept.getId()+",%";
		DeptExample example = new DeptExample();
		DeptExample.Criteria criteria = example.createCriteria();
		criteria.andLevelLike(queryLevel);
		List<Dept> deptList = deptMapper.selectByExample(example);
		return deptList;
	}

	private void updateWithChild(Dept before, Dept after) {
		//判断当前部门的父部门是否改变
		if (before.getParentId().equals(after.getParentId())) {
			deptMapper.updateByPrimaryKeySelective(after);
		}else {
			//遍历修改前的该部门的所有子部门,修改子部门的level值
			List<Dept> childDeptList = selectAllChildDeptList(before.getId());
			for (Dept childDept : childDeptList) {
				String newChildLevel = after.getLevel()+childDept.getLevel().substring(before.getLevel().length());
				childDept.setLevel(newChildLevel);
				//修改子部门列表
				deptMapper.updateByPrimaryKey(childDept);
			}
			deptMapper.updateByPrimaryKeySelective(after);
		}
	}

	@Override
	public List<Dept> selectAll() {
		List<Dept> deptList = deptMapper.selectByExample(null);
		return deptList;
	}

	public void test() {
		System.out.println("1");
		deptMapper.selectByPrimaryKey(1);
		System.out.println("2");
		deptMapper.selectByPrimaryKey(1);
		System.out.println("3");
		deptMapper.selectByPrimaryKey(2);
		System.out.println("4");
		deptMapper.selectByPrimaryKey(1);

	}

	@Override
	public PageInfo<Dept> selectAllByPage(PageDTO pageDTO) {
		ValidateUtil.validate(pageDTO);
		PageHelper.startPage(pageDTO.getPageNum(), pageDTO.getPageSize());
		List<Dept> deptList = deptMapper.selectByExample(null);
		PageInfo pageInfo = new PageInfo(deptList);
		return pageInfo;
	}

	@Override
	public List<DeptDTO> tree() {
		//查询所有部门
		List<Dept> deptList = selectAll();

		List<DeptDTO> deptDTOList = convertDeptList2DeptDTOList(deptList);

		//封装数据,根据level区分不同的部门列表
		//level->list<deptDTO>
		ArrayListMultimap<String, DeptDTO> deptLevelMap = ArrayListMultimap.create();
		List<DeptDTO> rootDeptList = Lists.newArrayList();

		for (DeptDTO deptDTO : deptDTOList) {
			deptLevelMap.put(deptDTO.getLevel(), deptDTO);

			//获取根部门列表.
			if (deptDTO.getLevel().equals(ROOT_LEVEL)) {
				rootDeptList.add(deptDTO);
			}
		}

		//排序
		Collections.sort(rootDeptList,deptComparator);

		//递归处理每层数据.设置childDeptList.
		transformDeptListToTree(rootDeptList, deptLevelMap);

		return rootDeptList;
	}



	/**
	 * 将部门列表 递归成 树形结构
	 */
	private void transformDeptListToTree(List<DeptDTO> deptDTOList, ArrayListMultimap<String, DeptDTO> deptLevelMap) {
		//遍历每个DTO,设置childDeptList
		//通过deptLevelMap的key(根据level)获取childDeptList
		for (DeptDTO deptDTO : deptDTOList) {
			String nextLevel = deptDTO.getLevel()+deptDTO.getId()+",";
			List<DeptDTO> childDeptList = deptLevelMap.get(nextLevel);
			if (CollectionUtils.isNotEmpty(childDeptList)) {
				Collections.sort(childDeptList,deptComparator);
				deptDTO.setChildDeptList(childDeptList);
				transformDeptListToTree(childDeptList,deptLevelMap);
			}
		}
	}

	/**
	 * 校验同级部门下是否存在相同名称的部门
	 *
	 * @param name
	 * @param parentId
	 * @param id
	 * @return
	 */
	private Boolean checkNameExist(String name, Integer parentId, Integer id) {
		DeptExample deptExample = new DeptExample();
		DeptExample.Criteria criteria = deptExample.createCriteria();
		criteria.andNameEqualTo(name);
		criteria.andParentIdEqualTo(parentId);
		if (id != null) {
			criteria.andIdNotEqualTo(id);
		}

		int count = deptMapper.countByExample(deptExample);
		if (count > 0) {
			return true;
		} else {
			return false;
		}
	}

	private DeptDTO convertDept2DeptDTO(Dept dept) {
		DeptDTO deptDTO = new DeptDTO();
		BeanUtils.copyProperties(dept, deptDTO);
		return deptDTO;
	}

	private List<DeptDTO> convertDeptList2DeptDTOList(List<Dept> deptList) {

		List<DeptDTO> deptDTOList = new ArrayList<>();
		for (Dept dept : deptList) {
			DeptDTO deptDTO = convertDept2DeptDTO(dept);
			deptDTOList.add(deptDTO);
		}

		return deptDTOList;
	}

	/**
	 * 计算等级
	 * 规则:
	 * 如果父部门为null,则level为0+','
	 * 如果父部门不为null,则level=parent.level+parentId+','
	 *
	 * @return
	 */
	private String calculateLevel(Dept parentDept) {
		Integer rootParentId = 0;
		String separator = ",";

		String level = "";
		log.debug("[计算等级]父部门={}", parentDept);
		if (parentDept == null) {
			level = rootParentId + separator;
		} else {
			level = parentDept.getLevel() + parentDept.getId() + separator;
		}

		return level;
	}

	//比较器
	private Comparator<DeptDTO> deptComparator = new Comparator<DeptDTO>() {
		@Override
		public int compare(DeptDTO o1, DeptDTO o2) {
			return o1.getSequence() - o2.getSequence();
		}
	};
}
